package org.phnq.babel;

import java.lang.reflect.*;
import java.util.*;
import org.phnq.babel.types.*;

/**
 * <<Class summary>>
 *
 * @author Patrick Gostovic &lt;&gt;
 * @version $Rev$
 */
public class ObjectFactory
{
	private static Map<String,String> classAliases = new HashMap<String,String>();
	private static List<ObjectFactoryDelegate> delegates = new ArrayList<ObjectFactoryDelegate>();
	
	public static void addClassAlias(String alias, String target)
	{
		classAliases.put(alias, target);
	}
	
	public static void addDelegate(ObjectFactoryDelegate delegate)
	{
		delegates.add(delegate);
	}
	
	public static JSValue createObject(JSArray args)
	{
		// Priority is given to the delegates
		for(ObjectFactoryDelegate delegate : delegates)
		{
			JSValue val = delegate.createObject(args);
			if(val != null)
				return val;
		}

		// If no delegate can fulfill the request then use reflection.
		String className = args.get(0).toString();
		className = classAliases.containsKey(className) ? classAliases.get(className) : className;
		
		try
		{
			Class c = Class.forName(className);
			Object o = c.newInstance();
			Method m = c.getMethod("createObject", JSArray.class);
			if(m.getReturnType().equals(JSValue.class))
			{
				return (JSValue)m.invoke(o, args);
			}
			else
			{
				// wrong rerturn type.
			}
		}
		catch(ClassNotFoundException ex)
		{
			// could not find named class.
			ex.printStackTrace();
		}
		catch(InstantiationException ex)
		{
			ex.printStackTrace();
		}
		catch(IllegalAccessException ex)
		{
			ex.printStackTrace();
		}
		catch(NoSuchMethodException ex)
		{
			// no createObject method found
			ex.printStackTrace();
		}
		catch(InvocationTargetException ex)
		{
			ex.printStackTrace();
		}

		return JSUndefined.getInstance();
	}
	
	public static interface ObjectFactoryDelegate
	{
		public JSValue createObject(JSArray args);
	}
}
